Autor
Un problema recurrente en la optimización de Layout (posición de los productos) es generar áreas con mapas de calor que representan el flujo de clientes, esta información es útil para saber que zonas de la tienda son mas concurridas y tiene un mayor flujo de personas de manera tal de posicionar los productos de mayor valor para en negocio en esa zona y/o reoptimizar en Layout. Este problema es tranversal en mutiples Industrias desde Retail, Centros Comerciales hasta un Casino.
Video de camara de seguridad de personas caminando en un centro comercial. Video de uso gratuito (Free Stock video footage YouTube)
Generar un sistema automatizado que permita:
import torchvision
import cv2
import matplotlib.pyplot as plt
from PIL import Image
from torchvision import datasets, models, transforms as T
Abrimos la Imagen
im = Image.open('Out\\frame0.jpg')
plt.imshow(im)
<matplotlib.image.AxesImage at 0x1d22fce8850>
img = cv2.imread('Out\\frame0.jpg') # Read image with cv2
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # Convert to RGB
Definimos un par de coordenadas
coor=[(443.22217, 432.3046), (495.6839, 569.45807)]
coor
[(443.22217, 432.3046), (495.6839, 569.45807)]
aux=tuple(tuple(map(int, tup)) for tup in coor) # transforma a entero
cv2.rectangle(img, aux[0],aux[1],color=(0, 255, 0), thickness=3)
cv2.putText(img,'Person',aux[0], cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0),thickness=3)
array([[[128, 128, 128],
[128, 128, 128],
[128, 128, 128],
...,
[148, 150, 147],
[149, 151, 148],
[149, 151, 148]],
[[128, 128, 128],
[128, 128, 128],
[128, 128, 128],
...,
[148, 150, 147],
[149, 151, 148],
[149, 151, 148]],
[[128, 128, 128],
[128, 128, 128],
[128, 128, 128],
...,
[148, 150, 147],
[148, 150, 147],
[149, 151, 148]],
...,
[[200, 202, 199],
[201, 203, 200],
[199, 201, 198],
...,
[229, 229, 229],
[229, 229, 229],
[229, 229, 229]],
[[200, 202, 199],
[200, 202, 199],
[201, 203, 200],
...,
[229, 229, 229],
[229, 229, 229],
[229, 229, 229]],
[[200, 202, 199],
[199, 201, 198],
[202, 204, 201],
...,
[229, 229, 229],
[229, 229, 229],
[229, 229, 229]]], dtype=uint8)
Graficamos la imagen con el recuadro y el label "Person"
plt.imshow(img)
<matplotlib.image.AxesImage at 0x1d2302bd3c0>
Importaremos una restnet pre-entrenada y el label de los disntos objetos que detecta
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
model.eval()
COCO_INSTANCE_CATEGORY_NAMES = [
'__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A', 'stop sign',
'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack', 'umbrella', 'N/A', 'N/A',
'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
'bottle', 'N/A', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl',
'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table',
'N/A', 'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A', 'book',
'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'
]
C:\Users\Usuario\.conda\envs\cv\lib\site-packages\torchvision\models\_utils.py:208: UserWarning: The parameter 'pretrained' is deprecated since 0.13 and may be removed in the future, please use 'weights' instead. warnings.warn( C:\Users\Usuario\.conda\envs\cv\lib\site-packages\torchvision\models\_utils.py:223: UserWarning: Arguments other than a weight enum or `None` for 'weights' are deprecated since 0.13 and may be removed in the future. The current behavior is equivalent to passing `weights=FasterRCNN_ResNet50_FPN_Weights.COCO_V1`. You can also use `weights=FasterRCNN_ResNet50_FPN_Weights.DEFAULT` to get the most up-to-date weights. warnings.warn(msg)
def get_prediction(img_path, threshold):
"""
Realiza una predicción de detección de objetos en una imagen utilizando un modelo pre-entrenado.
Parámetros:
- img_path (str): Ruta de la imagen de entrada.
- threshold (float): Umbral de confianza para filtrar las predicciones.
Retorna:
- pred_boxes1 (list): Lista de cajas delimitadoras (bounding boxes) de los objetos detectados en la imagen.
- pred_class1 (list): Lista de clases de los objetos detectados en la imagen.
"""
img = Image.open(img_path) # Cargar la imagen
transform = T.Compose([T.ToTensor()]) # Definir la transformación de PyTorch
img = transform(img) # Aplicar la transformación a la imagen
pred = model([img]) # Pasar la imagen al modelo para obtener las predicciones
# Obtener la clase de la predicción y su puntuación
pred_class = [COCO_INSTANCE_CATEGORY_NAMES[i] for i in list(pred[0]['labels'].numpy())]
pred_boxes = [[(i[0], i[1]), (i[2], i[3])] for i in list(pred[0]['boxes'].detach().numpy())]
pred_score = list(pred[0]['scores'].detach().numpy())
# Filtrar las predicciones basadas en el umbral de confianza
pred_t = [pred_score.index(x) for x in pred_score if x > threshold][-1]
pred_boxes = pred_boxes[:pred_t+1]
pred_class = pred_class[:pred_t+1]
# Filtrar solo las predicciones de la clase 'person'
myIndices = [i for i in range(len(pred_class)) if pred_class[i] == 'person']
pred_class1 = [pred_class[i] for i in myIndices]
pred_boxes1 = [pred_boxes[i] for i in myIndices]
return pred_boxes1, pred_class1
def object_detection_api(img_path, threshold=0.5, rect_th=3, text_size=3, text_th=3):
"""
Realiza la detección de objetos en una imagen y muestra el resultado visualmente.
Parámetros:
- img_path (str): Ruta de la imagen de entrada.
- threshold (float, opcional): Umbral de confianza para filtrar las predicciones (por defecto es 0.5).
- rect_th (int, opcional): Grosor del contorno de las cajas delimitadoras (por defecto es 3).
- text_size (int, opcional): Tamaño del texto de las etiquetas (por defecto es 3).
- text_th (int, opcional): Grosor del texto de las etiquetas (por defecto es 3).
Retorna:
- len(boxes): la cantidad de objetos (personas) detectados en la imagen.
"""
boxes, pred_cls = get_prediction(img_path, threshold) # Obtener las predicciones de detección de objetos
img = cv2.imread(img_path) # Leer la imagen utilizando OpenCV
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # Convertir la imagen de BGR a RGB
# Dibujar las cajas delimitadoras y etiquetas en la imagen
for i in range(len(boxes)):
aux = tuple(tuple(map(int, tup)) for tup in boxes[i])
cv2.rectangle(img, aux[0], aux[1], color=(0, 255, 0), thickness=rect_th) # Dibujar el contorno de la caja delimitadora
cv2.putText(img, str(i), aux[0], cv2.FONT_HERSHEY_SIMPLEX, text_size, (0, 255, 0), thickness=text_th) # Mostrar la etiqueta del objeto
plt.figure(figsize=(20, 30))
plt.imshow(img)
plt.xticks([])
plt.yticks([])
plt.show() # Mostrar la figura
return len(boxes)
def object_detection_api_without_plot(img_path, threshold=0.5, rect_th=3, text_size=3, text_th=3):
"""
Realiza la detección de objetos en una imagen y muestra el resultado visualmente.
Parámetros:
- img_path (str): Ruta de la imagen de entrada.
- threshold (float, opcional): Umbral de confianza para filtrar las predicciones (por defecto es 0.5).
Retorna:
- len(boxes): la cantidad de objetos (personas) detectados en la imagen.
"""
boxes, pred_cls = get_prediction(img_path, threshold) # Obtener las predicciones de detección de objetos
return len(boxes)
boxes, pred_cls = get_prediction('Out\\frame0.jpg', 0.8)
boxes
[[(443.22217, 432.3046), (495.6839, 569.45807)], [(501.18707, 300.63504), (548.6047, 415.24503)], [(966.0561, 213.89882), (1010.95636, 321.63043)], [(775.5949, 99.51255), (807.30255, 185.5091)], [(173.25558, 290.7064), (221.5165, 404.7594)], [(1195.2103, 97.64532), (1234.1835, 183.02487)], [(974.37933, 314.29733), (1028.7239, 427.42883)], [(803.32416, 87.04374), (835.83984, 177.20128)], [(760.0624, 635.7334), (827.81213, 719.68994)], [(615.11206, 115.60903), (658.35144, 204.57394)], [(945.49585, 470.17923), (1012.7888, 586.4515)], [(759.35046, 338.6047), (807.22565, 437.8828)], [(133.52132, 29.448956), (174.58212, 107.219475)], [(471.4505, 159.81447), (511.04123, 257.3289)], [(228.30536, 330.32376), (267.24747, 428.82764)], [(59.997746, 87.70881), (95.77105, 168.62614)], [(1074.6514, 10.540487), (1103.3835, 83.69601)], [(378.01562, 178.02309), (418.84055, 270.67245)], [(260.2885, 342.58185), (302.42795, 447.8906)], [(1053.0913, 12.96877), (1081.9692, 81.528984)], [(924.1393, 0.8561452), (960.6697, 122.83047)], [(100.124954, 1.5615566), (132.55731, 35.11881)], [(657.0554, 67.776184), (691.8573, 155.52673)], [(871.3717, 6.7900934), (896.13574, 73.67567)], [(727.94006, 30.92497), (755.0558, 97.640015)], [(531.54846, 51.92416), (564.2414, 136.32295)], [(485.63174, 4.369262), (513.7344, 73.45789)], [(21.844887, 530.03906), (92.2304, 656.13727)], [(1113.8655, 7.714753), (1150.1993, 90.23451)], [(231.45007, 4.2224317), (269.77887, 94.30402)], [(568.6086, 46.845814), (595.85565, 133.0215)], [(596.371, 65.716286), (621.37915, 143.22125)], [(1214.0133, 0.0), (1235.3495, 34.20509)], [(281.86777, 338.0434), (329.47772, 430.5924)], [(304.13635, 342.21066), (338.56122, 423.18076)], [(1145.718, 54.933544), (1187.6442, 133.9454)], [(1264.701, 66.73807), (1280.0, 126.33597)]]
pred_cls
['person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person']
a=object_detection_api('Out\\frame0.jpg', threshold=0.8, text_size=1)
a
37
Detectó 37 personas en esta imagen con el umbral de 80%
Modificarémos los umbrales (threshold) de detección para ver como varía la detección de personas de la RestNet utilizando distintos umbrales.
b=object_detection_api('Out\\frame0.jpg', threshold=0.99, text_size=1)
b=object_detection_api('Out\\frame0.jpg', threshold=0.5, text_size=1)
b
44
Detectó 44 personas en esta imagen con el umbral de 50%
Usaremos una imagen de referencia para crear un heat map con el centroide de la detección
boxes, pred_cls = get_prediction('Out\\frame0.jpg', 0.5)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.DataFrame(boxes, columns=['par1', 'par2'])
# Splitting the 'lat_long' column into two separate columns
df[['x1', 'y1']] = df['par1'].apply(pd.Series)
df[['x2', 'y2']] = df['par2'].apply(pd.Series)
df['x1']=df['x1'].astype(int)
df['y1']=df['y1'].astype(int)
df['x2']=df['x2'].astype(int)
df['y2']=df['y2'].astype(int)
df['xmean']=(df['x1']+df['x2'])/2
df['ymean']=(df['y1']+df['y2'])/2
x =df['xmean']
y =df['ymean']
plt.hist2d(x,y, bins=[np.arange(0,1280,10),np.arange(0,720,10)])
plt.gca().invert_yaxis()
Comparamos el Heat Map con la foto real para confirmar que el grafico este correcto
im = Image.open('Out\\frame0.jpg')
plt.imshow(im)
<matplotlib.image.AxesImage at 0x1d23c7e7880>
from datetime import datetime
import pandas as pd
import seaborn as sns
a=[]
q=[]
for i in range (0,136):
start_time = datetime.now() # grabar el tiempo al inicio de cada iteración
q1=object_detection_api_without_plot("Out\\frame%i.jpg" % i, threshold=0.8, text_size=1)
end_time = datetime.now() # grabar el tiempo al finalizar cada predicción
total=end_time - start_time
print('Duration: {}'.format(total))
a.append(total.total_seconds())
q.append(q1) # agregar a una lista la cantidad de segundos de cada iteración
Duration: 0:00:03.477468 Duration: 0:00:03.455627 Duration: 0:00:03.349561 Duration: 0:00:03.038808 Duration: 0:00:03.029607 Duration: 0:00:03.597913 Duration: 0:00:03.462557 Duration: 0:00:03.569637 Duration: 0:00:03.328516 Duration: 0:00:03.703719 Duration: 0:00:04.081351 Duration: 0:00:03.168633 Duration: 0:00:03.143573 Duration: 0:00:03.130546 Duration: 0:00:03.201127 Duration: 0:00:02.976145 Duration: 0:00:03.985306 Duration: 0:00:03.505713 Duration: 0:00:03.031217 Duration: 0:00:03.061782 Duration: 0:00:03.400111 Duration: 0:00:03.112522 Duration: 0:00:03.105371 Duration: 0:00:03.238456 Duration: 0:00:02.933087 Duration: 0:00:04.027796 Duration: 0:00:03.534075 Duration: 0:00:03.137903 Duration: 0:00:03.028016 Duration: 0:00:03.097845 Duration: 0:00:02.928870 Duration: 0:00:03.072282 Duration: 0:00:03.086602 Duration: 0:00:03.131398 Duration: 0:00:03.145754 Duration: 0:00:03.368542 Duration: 0:00:03.757996 Duration: 0:00:03.463804 Duration: 0:00:03.127896 Duration: 0:00:03.179658 Duration: 0:00:03.044450 Duration: 0:00:03.176788 Duration: 0:00:03.025282 Duration: 0:00:03.097436 Duration: 0:00:03.032008 Duration: 0:00:03.079955 Duration: 0:00:03.039836 Duration: 0:00:03.130766 Duration: 0:00:03.182610 Duration: 0:00:03.311971 Duration: 0:00:03.254760 Duration: 0:00:03.148362 Duration: 0:00:03.345377 Duration: 0:00:03.282234 Duration: 0:00:03.032623 Duration: 0:00:03.072148 Duration: 0:00:03.268346 Duration: 0:00:03.385920 Duration: 0:00:02.945458 Duration: 0:00:02.968667 Duration: 0:00:03.293309 Duration: 0:00:03.377194 Duration: 0:00:03.007043 Duration: 0:00:03.766000 Duration: 0:00:03.731162 Duration: 0:00:03.129318 Duration: 0:00:02.883450 Duration: 0:00:02.979545 Duration: 0:00:02.953491 Duration: 0:00:02.995939 Duration: 0:00:03.019846 Duration: 0:00:03.042848 Duration: 0:00:02.880998 Duration: 0:00:03.222097 Duration: 0:00:02.937458 Duration: 0:00:02.954649 Duration: 0:00:03.004023 Duration: 0:00:02.908451 Duration: 0:00:02.996545 Duration: 0:00:02.975183 Duration: 0:00:02.842713 Duration: 0:00:03.088294 Duration: 0:00:02.894740 Duration: 0:00:02.884184 Duration: 0:00:02.955321 Duration: 0:00:02.872028 Duration: 0:00:02.882997 Duration: 0:00:02.904756 Duration: 0:00:02.914393 Duration: 0:00:02.876630 Duration: 0:00:02.854172 Duration: 0:00:02.983024 Duration: 0:00:02.866874 Duration: 0:00:02.877342 Duration: 0:00:02.886569 Duration: 0:00:02.917564 Duration: 0:00:03.038374 Duration: 0:00:02.876570 Duration: 0:00:02.926714 Duration: 0:00:02.902250 Duration: 0:00:02.949982 Duration: 0:00:03.185080 Duration: 0:00:03.214656 Duration: 0:00:03.094802 Duration: 0:00:03.000047 Duration: 0:00:02.994071 Duration: 0:00:03.152516 Duration: 0:00:03.092038 Duration: 0:00:03.739364 Duration: 0:00:03.065818 Duration: 0:00:03.147165 Duration: 0:00:03.630099 Duration: 0:00:03.426025 Duration: 0:00:03.669775 Duration: 0:00:03.681535 Duration: 0:00:03.437565 Duration: 0:00:03.314245 Duration: 0:00:03.189518 Duration: 0:00:03.408209 Duration: 0:00:03.681147 Duration: 0:00:03.460315 Duration: 0:00:04.816128 Duration: 0:00:05.432338 Duration: 0:00:04.782818 Duration: 0:00:04.561741 Duration: 0:00:03.438461 Duration: 0:00:03.444109 Duration: 0:00:03.360569 Duration: 0:00:03.669406 Duration: 0:00:03.557897 Duration: 0:00:03.150764 Duration: 0:00:03.072196 Duration: 0:00:03.163625 Duration: 0:00:03.219815 Duration: 0:00:03.212050 Duration: 0:00:02.975588
a2=[]
q2=[]
box=[]
for i in range (0,136):
start_time = datetime.now() # grabar el tiempo al inicio de cada iteración
boxes, pred_cls = get_prediction("Out\\frame%i.jpg" % i, 0.5)
q1=object_detection_api_without_plot("Out\\frame%i.jpg" % i, threshold=0.5, text_size=1)
end_time = datetime.now() # grabar el tiempo al finalizar cada predicción
total=end_time - start_time
print('Duration: {}'.format(total))
a2.append(total.total_seconds())
q2.append(q1) # agregar a una lista la cantidad de segundos de cada iteración
box.append(boxes)
Duration: 0:00:06.596606 Duration: 0:00:06.810957 Duration: 0:00:06.659540 Duration: 0:00:06.825866 Duration: 0:00:07.800866 Duration: 0:00:08.372996 Duration: 0:00:06.666737 Duration: 0:00:06.450156 Duration: 0:00:06.796775 Duration: 0:00:06.724257 Duration: 0:00:06.598453 Duration: 0:00:06.727366 Duration: 0:00:06.767956 Duration: 0:00:06.226181 Duration: 0:00:06.049187 Duration: 0:00:05.944107 Duration: 0:00:05.984675 Duration: 0:00:05.852392 Duration: 0:00:05.860287 Duration: 0:00:06.022663 Duration: 0:00:06.376641 Duration: 0:00:05.835493 Duration: 0:00:06.089443 Duration: 0:00:06.339559 Duration: 0:00:06.482644 Duration: 0:00:06.249502 Duration: 0:00:06.521721 Duration: 0:00:06.969412 Duration: 0:00:06.570502 Duration: 0:00:06.431079 Duration: 0:00:06.228738 Duration: 0:00:06.161716 Duration: 0:00:06.169368 Duration: 0:00:06.022433 Duration: 0:00:05.995674 Duration: 0:00:06.710109 Duration: 0:00:05.990407 Duration: 0:00:06.367969 Duration: 0:00:06.047187 Duration: 0:00:06.026206 Duration: 0:00:06.203654 Duration: 0:00:05.999995 Duration: 0:00:06.805040 Duration: 0:00:07.187817 Duration: 0:00:07.016086 Duration: 0:00:06.355007 Duration: 0:00:06.985449 Duration: 0:00:06.588185 Duration: 0:00:06.593221 Duration: 0:00:06.525539 Duration: 0:00:06.175297 Duration: 0:00:06.262076 Duration: 0:00:06.324680 Duration: 0:00:06.375045 Duration: 0:00:06.716227 Duration: 0:00:06.158418 Duration: 0:00:06.094979 Duration: 0:00:07.066368 Duration: 0:00:06.485178 Duration: 0:00:06.299164 Duration: 0:00:06.231758 Duration: 0:00:06.542005 Duration: 0:00:06.407392 Duration: 0:00:06.600131 Duration: 0:00:06.404667 Duration: 0:00:06.397865 Duration: 0:00:06.342808 Duration: 0:00:06.926023 Duration: 0:00:06.924490 Duration: 0:00:06.459600 Duration: 0:00:06.279892 Duration: 0:00:06.298043 Duration: 0:00:06.686645 Duration: 0:00:06.216372 Duration: 0:00:05.954757 Duration: 0:00:06.102213 Duration: 0:00:05.915516 Duration: 0:00:06.045349 Duration: 0:00:06.141603 Duration: 0:00:06.101974 Duration: 0:00:05.908459 Duration: 0:00:05.746497 Duration: 0:00:05.971676 Duration: 0:00:06.581387 Duration: 0:00:06.472023 Duration: 0:00:06.359681 Duration: 0:00:06.615011 Duration: 0:00:06.108421 Duration: 0:00:05.963362 Duration: 0:00:06.214528 Duration: 0:00:06.679923 Duration: 0:00:07.072498 Duration: 0:00:06.780616 Duration: 0:00:06.700573 Duration: 0:00:06.346705 Duration: 0:00:06.147339 Duration: 0:00:06.086752 Duration: 0:00:06.324896 Duration: 0:00:06.612091 Duration: 0:00:06.205655 Duration: 0:00:05.845059 Duration: 0:00:05.879961 Duration: 0:00:05.836137 Duration: 0:00:05.893570 Duration: 0:00:05.734879 Duration: 0:00:05.777898 Duration: 0:00:06.347659 Duration: 0:00:06.671724 Duration: 0:00:06.353454 Duration: 0:00:05.773754 Duration: 0:00:05.786047 Duration: 0:00:06.439009 Duration: 0:00:06.873638 Duration: 0:00:06.619458 Duration: 0:00:06.960732 Duration: 0:00:06.723467 Duration: 0:00:06.648762 Duration: 0:00:06.612932 Duration: 0:00:06.502028 Duration: 0:00:06.205317 Duration: 0:00:06.241760 Duration: 0:00:06.427285 Duration: 0:00:06.167727 Duration: 0:00:06.868486 Duration: 0:00:06.267513 Duration: 0:00:06.022302 Duration: 0:00:06.011519 Duration: 0:00:06.180361 Duration: 0:00:06.471297 Duration: 0:00:06.309113 Duration: 0:00:06.325057 Duration: 0:00:06.549484 Duration: 0:00:06.175435 Duration: 0:00:06.226722 Duration: 0:00:07.129457 Duration: 0:00:06.945828
df_concat=pd.DataFrame()
for i in range(0,136):
df1 = pd.DataFrame(box[i], columns=['par1', 'par2'])
# Splitting the 'lat_long' column into two separate columns
df1[['x1', 'y1']] = df1['par1'].apply(pd.Series)
df1[['x2', 'y2']] = df1['par2'].apply(pd.Series)
df1['x1']=df1['x1'].astype(int)
df1['y1']=df1['y1'].astype(int)
df1['x2']=df1['x2'].astype(int)
df1['y2']=df1['y2'].astype(int)
df1['xmean']=(df1['x1']+df1['x2'])/2
df1['ymean']=(df1['y1']+df1['y2'])/2
df_concat=pd.concat([df_concat,df1])
df = pd.DataFrame({'Duración':a})
df.describe()
| Duración | |
|---|---|
| count | 136.000000 |
| mean | 3.240421 |
| std | 0.397914 |
| min | 2.842713 |
| 25% | 2.995472 |
| 50% | 3.130656 |
| 75% | 3.379376 |
| max | 5.432338 |
sns.histplot(data=df, x="Duración")
<Axes: xlabel='Duración', ylabel='Count'>
df1 = pd.DataFrame({'Cantidad':q})
df1.describe()
| Cantidad | |
|---|---|
| count | 136.000000 |
| mean | 33.617647 |
| std | 3.806542 |
| min | 26.000000 |
| 25% | 31.000000 |
| 50% | 33.000000 |
| 75% | 37.000000 |
| max | 42.000000 |
sns.histplot(data=df1, x="Cantidad")
<Axes: xlabel='Cantidad', ylabel='Count'>
df_concat
| par1 | par2 | x1 | y1 | x2 | y2 | xmean | ymean | |
|---|---|---|---|---|---|---|---|---|
| 0 | (443.22217, 432.3046) | (495.6839, 569.45807) | 443 | 432 | 495 | 569 | 469.0 | 500.5 |
| 1 | (501.18707, 300.63504) | (548.6047, 415.24503) | 501 | 300 | 548 | 415 | 524.5 | 357.5 |
| 2 | (966.0561, 213.89882) | (1010.95636, 321.63043) | 966 | 213 | 1010 | 321 | 988.0 | 267.0 |
| 3 | (775.5949, 99.51255) | (807.30255, 185.5091) | 775 | 99 | 807 | 185 | 791.0 | 142.0 |
| 4 | (173.25558, 290.7064) | (221.5165, 404.7594) | 173 | 290 | 221 | 404 | 197.0 | 347.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 34 | (763.8143, 0.58402455) | (785.24835, 47.05696) | 763 | 0 | 785 | 47 | 774.0 | 23.5 |
| 35 | (415.5593, 0.0) | (442.8612, 36.811195) | 415 | 0 | 442 | 36 | 428.5 | 18.0 |
| 36 | (924.0795, 617.972) | (994.36, 702.72516) | 924 | 617 | 994 | 702 | 959.0 | 659.5 |
| 37 | (752.81573, 2.0422451) | (778.64526, 46.801693) | 752 | 2 | 778 | 46 | 765.0 | 24.0 |
| 38 | (240.47375, 305.00726) | (291.56476, 416.08606) | 240 | 305 | 291 | 416 | 265.5 | 360.5 |
5367 rows × 8 columns
x =df_concat['xmean']
y =df_concat['ymean']
plt.hist2d(x,y, bins=[np.arange(0,1280,20),np.arange(0,720,20)])
plt.gca().invert_yaxis()
l=range(0,136)
accuracy = pd.DataFrame(list(zip(l, q, q2)),columns =['Tiempo', 'Modelo_1_80%', 'Modelo_2_50%'])
accuracy2=accuracy.stack().reset_index()
accuracy3=accuracy2[accuracy2['level_1']!='Tiempo']
accuracy3=accuracy3.rename(columns={accuracy3.columns[2]: "Cantidad"})
accuracy3=accuracy3.rename(columns={accuracy3.columns[0]: "Segundos"})
accuracy3=accuracy3.rename(columns={accuracy3.columns[1]: "Y"})
accuracy3
| Segundos | Y | Cantidad | |
|---|---|---|---|
| 1 | 0 | Modelo_1_80% | 37 |
| 2 | 0 | Modelo_2_50% | 44 |
| 4 | 1 | Modelo_1_80% | 38 |
| 5 | 1 | Modelo_2_50% | 46 |
| 7 | 2 | Modelo_1_80% | 38 |
| ... | ... | ... | ... |
| 401 | 133 | Modelo_2_50% | 34 |
| 403 | 134 | Modelo_1_80% | 30 |
| 404 | 134 | Modelo_2_50% | 37 |
| 406 | 135 | Modelo_1_80% | 30 |
| 407 | 135 | Modelo_2_50% | 39 |
272 rows × 3 columns
import plotly.express as px
fig = px.line(accuracy3, x='Segundos', y='Cantidad', color='Y', markers=True, title='Detección de Personas por Modelo')
fig.show()
Sin embargo este punto es rápidamente mejorado al llevar el umbral a 50% de detección y, con esto, se alcanza un accuracy del 100%, es decir, se detecta exactamente la misma cantidad de personas que hay en la imagen validado con supervión humana. Se realiza un grafico comparativo s con la cantidad de personas detectada por cada algoritmo para cada cuadro en función del tiempo. Se observa que el modelo de detección con umbral del 50% detecta para cada cuadro más imagenes que el modelo con umbral de detección de 80%.
Finalmente se realiza un analisis de áreas de interes, el cual tiene el mayor valor para una aplicación de negocio real. Este mismo prototipo podría ser utilizado para medir flujo de personas en cualquier retail, más aun, detectar zonas de interés relevantes que concentren mayor cantidad o flujo de personas.